#include <stdio.h>
#include <sys/time.h>

#include "h_thread.h"

namespace h_base
{
// HThread

HThread::HThread()
{
}

HThread::~HThread()
{
}

void *HThread::ThreadFunc(void *Arg)
{
   HThread *This = (HThread*)Arg;
   This->Execute();
   return NULL;
}

void HThread::Start(int StackSize)
{
   if ( StackSize == 0 )
   {
      pthread_create(&FTid, NULL, ThreadFunc, (void*)this);
   }
   else
   {
      pthread_attr_t ThreadAttr;
      pthread_attr_init(&ThreadAttr); 
      pthread_attr_setstacksize(&ThreadAttr, StackSize);
      int r = pthread_create(&FTid, &ThreadAttr, ThreadFunc, (void*)this);
      if ( r != 0 )
      {
         fprintf(stderr, "pthread_create fail, errno = %d\n", r);
      }
   }
}

void HThread::Wait()
{
   void *Status;
   pthread_join(FTid, &Status);
}

pthread_t HThread::GetTid()
{
   return FTid;
}

// HMutex

HMutex::HMutex()
{
   pthread_mutex_init(&FMutex, NULL);
}

HMutex::~HMutex()
{
   pthread_mutex_destroy(&FMutex);
}

void HMutex::Lock()
{
   pthread_mutex_lock(&FMutex);
}


void HMutex::Unlock()
{
   pthread_mutex_unlock(&FMutex);
}


// HThreadCond

HThreadCond::HThreadCond(HMutex *AMutex)
   : FMutex(AMutex)
{
   pthread_cond_init(&FCond, NULL);
}

HThreadCond::~HThreadCond()
{
   pthread_cond_destroy(&FCond);
}

void HThreadCond::Wait()
{
   pthread_cond_wait(&FCond, FMutex->GetPthreadMutex());
}

bool HThreadCond::TimedWait(int Millisecond)
{
   struct timeval TimeVal;
   struct timespec TimeSpec;

   gettimeofday(&TimeVal, NULL);
   TimeVal.tv_sec += Millisecond / 1000;
   TimeVal.tv_usec += Millisecond % 1000 * 1000;

   if ( TimeVal.tv_usec >= 1000 * 1000 )
   {
      TimeVal.tv_sec++;
      TimeVal.tv_usec -= 1000 * 1000;
   }

   TimeSpec.tv_sec = TimeVal.tv_sec;
   TimeSpec.tv_nsec = TimeVal.tv_usec * 1000;
 
   int r = pthread_cond_timedwait(&FCond, FMutex->GetPthreadMutex(), &TimeSpec);

   return r == 0;
}

void HThreadCond::Signal()
{
   pthread_cond_signal(&FCond);
}

void HThreadCond::Broadcast()
{
   pthread_cond_broadcast(&FCond);
}

}; // namespace h_base
